這裡稍微複習一下,JS 中的 this
會由於調用方式不同而改變指向的物件,基本上有以下幾種:
this
在 strict mode
下指向 undefined
,除此之外指向全域物件call
、apply
或 bind
調用函式new
綁定(new
Binding):綁定的物件透過 new
調用(建構子調用)產生this
固定指向外圍函式的詞法作用域。那麼,當不同綁定同時出現時,會以何者為優先呢?
首先是默認綁定,這個在最開始就說了,當函式未使用其他綁定方式時,this
便會指向默認值,因此無疑是所有綁定中優先度最低的。
接著來看看隱含綁定和明確綁定:
function foo() {
console.log( this.a );
}
var obj1 = {
a: "obj1",
foo: foo
};
var obj2 = {
a: "obj2",
foo: foo
};
obj1.foo(); // obj1
obj2.foo(); // obj2
obj1.foo.call( obj2 ); // obj2
obj2.foo.call( obj1 ); // obj1
從以上的結果看來,明確綁定毫無疑問優先於隱含綁定。
再來是 new
綁定和隱含綁定:
function foo(something) {
this.a = something;
}
var obj1 = { foo: foo };
var obj2 = {};
obj1.foo("Implicit Binding");
var bar = new obj1.foo("new Binding");
console.log(obj1.a); // Implicit Binding
console.log(bar.a); // new Binding
這裡也是毫無疑問的, new
綁定優先於隱含綁定。
那麼最後的最後,明確綁定和 new
綁定誰先誰後呢?
由於 new foo.call(obj1)
這樣的程式碼並不合法,也就是說無法同時執行明確綁定和 new
綁定,因此下面用 bind
方法回傳一個新的函式來進行比較:
function foo(something) {
this.a = something;
}
var obj1 = {};
var bindHelper = foo.bind(obj1);
bindHelper("Explicit Binding");
var newBinding = new bindHelper("new Binding");
console.log(obj1 === newBinding); // false
console.log(obj1.a); // Explicit Binding
console.log(newBinding.a); // new Binding
上面可以看到,用 new
調用函式的物件,和原本 bind
在 bindHelper
方法上的 obj
是不同的物件,也就是說 使用 new
創造的物件與原本綁定的物件完全無關,可說是直接覆蓋了 bind
給 bindHelper
函式的物件。
這樣一來,我們就能知道當同時出現不同綁定方式時,該如何判定它們彼此的優先順序了:
new
綁定:如果函式是透過 new
關鍵字調用的,那它的 this
就指向函式建構出來的新物件。call
、apply
調用,或者由 bind
包裝的函式,則 this
指向傳入 call
、apply
或 bind
的物件。this
固定指向詞法作用域。